from interaction20 import Interaction20
from experimentoutput import pickOtherExperiment

# Lesson 3 Interaction Derived Class 2 (Primitive Or Composite Type Interaction) for weighted anticipations
# Properties for Primitive Type
# preInteraction = None
# enactedInteraction => (self.experiment, self.result, self.valence)

# Properties for Composite Type
# preInteraction = Interaction(experiment, result, '') => contextInteraction
# postInteraction => (self.experiment, self.result,'') => enactedInteraction

class Interaction31(Interaction20):
    def __init__(self, contextInteraction, enactedInteraction):
        super().__init__(enactedInteraction.experiment, enactedInteraction.result, enactedInteraction.valence)
        self.preInteraction = contextInteraction
        self.weight = 1
        self.proclivity = 'NA'

    def __repr__(self):
        if self.preInteraction is not None:
            return '[({},{}) , ({},{})], {}'.format(self.preInteraction.experiment, self.preInteraction.result,
                                                    self.experiment, self.result, 'Weight: ' + str(self.weight))
        else:
            return '({},{},{}{})'.format(self.experiment, self.result, self.valence,
                                         ('' if str(self.proclivity) == 'NA' else ',' + str(self.proclivity)))

    # Override - get Interaction Name
    def getInteractionName(self):
        interationName = (self.preInteraction.experiment + self.preInteraction.result) if self.preInteraction is not None else ''
        interationName += super().getInteractionName()
        return interationName

    # Store new Primitive Interaction
    @classmethod
    def createPrimitiveInteraction(cls, experiment, result, valence):
        key = experiment + result
        if key not in cls.dictInteraction:
            inter = Interaction31(None, Interaction20(experiment, result, valence))
            cls.dictInteraction[key] = inter

    #Store new Composite Interaction
    @classmethod
    def learnCompositeInteraction(cls, contextInteraction, enactedInteraction):
        if contextInteraction is not None and enactedInteraction is not None:
            key = contextInteraction.experiment + contextInteraction.result + enactedInteraction.experiment + enactedInteraction.result
            if key in cls.dictInteraction:
                inter = cls.dictInteraction[key]
                inter.weight += 1
                print(' ' * 98, ' Upgrade Learning ', inter)
            else:
                inter = Interaction31(contextInteraction, enactedInteraction)
                cls.dictInteraction[key] = inter
                print(' ' * 78, ' Learn ', inter)

    #Anticipate next Interaction
    @classmethod
    def anticipate(cls, enactedInteraction):
        dictAnticipations = {}
        if enactedInteraction is not None:
            for interactionKey in cls.dictInteraction:
                interaction = cls.dictInteraction[interactionKey]
                if interaction.preInteraction is not None:
                    if interaction.preInteraction.getInteractionName() == enactedInteraction.getInteractionName():
                        #Anticipate the postInteraction
                        key = interaction.experiment + interaction.result
                        if key in dictAnticipations:
                            dictAnticipations[key].proclivity += (interaction.weight * interaction.valence)
                        else:
                            proposedAnticipation = Interaction31(None, interaction)
                            proposedAnticipation.proclivity = interaction.weight * interaction.valence
                            dictAnticipations[key] = proposedAnticipation
        for key in dictAnticipations:
            print(' ' * 52, ' Afforded ', dictAnticipations[key])
        return dictAnticipations

    #Choose Next Experiment based on anticipation
    @classmethod
    def selectExperiment(cls, dictAnticipations, randomFlag = False, lastExperiment = ''):
        # Sort by decreasing proclivity
        listAnticipations = list(dictAnticipations.values())
        listAnticipations.sort(key=lambda x: x.valence, reverse=True)

        #expNext = ''
        #for interaction in listAnticipations:
        if len(listAnticipations)>0:
            interaction = listAnticipations[0]
            if interaction.proclivity >= 0:
                expNext = interaction.experiment
                print('Next Afforded Experiment: ' + expNext)
        #        break
            else:
                print(' ' * 52, ' Negative Afforded Proclivity(s)')
                expNext = pickOtherExperiment(interaction.experiment, randomFlag, False)
        #        break
        else:
            expNext = pickOtherExperiment(lastExperiment, randomFlag, False)

        return expNext